﻿using System;
using System.Runtime.InteropServices;

namespace IOP.Extension.Convert
{
    /// <summary>
    /// 结构体转换扩展
    /// </summary>
    public static class StructConvertExtension
    {
        /// <summary>
        /// 将结构体转换为字节数组
        /// </summary>
        /// <typeparam name="TStruct"></typeparam>
        /// <param name="struct"></param>
        /// <returns></returns>
        public static byte[] StructToBytes<TStruct>(this TStruct @struct)
            where TStruct : struct
        {
            int size = Marshal.SizeOf(@struct);
            byte[] bytes = new byte[size];
            IntPtr structPtr = Marshal.AllocHGlobal(size);
            Marshal.StructureToPtr(@struct, structPtr, false);
            Marshal.Copy(structPtr, bytes, 0, size);
            Marshal.FreeHGlobal(structPtr);
            return bytes;
        }

        /// <summary>
        /// 将字节数组转换为结构体
        /// </summary>
        /// <typeparam name="TStruct"></typeparam>
        /// <param name="bytes"></param>
        /// <returns></returns>
        public static TStruct BytesToStruct<TStruct>(this byte[] bytes)
            where TStruct : struct
        {
            Type type = typeof(TStruct);
            int size = Marshal.SizeOf(type);
            if (size > bytes.Length) throw new ArgumentOutOfRangeException(nameof(bytes), $"this bytes length is biger than {nameof(TStruct)}'s size");
            IntPtr structPtr = Marshal.AllocHGlobal(size);
            Marshal.Copy(bytes, 0, structPtr, size);
            TStruct obj = Marshal.PtrToStructure<TStruct>(structPtr);
            Marshal.FreeHGlobal(structPtr);
            return obj;
        }
    }
}
